/**
 * @file	halPeripheral.c
 * @author	chipsea
 * @brief	
 * @version	0.1
 * @date	2020-11-30
 * @copyright Copyright (c) 2020, CHIPSEA Co., Ltd.
 * @note
 */

/*********************************************************************
 * INCLUDES
 */
#include "sdk_config.h"
#include "log.h"
#include "key.h"
#include "OSAL.h"
#include "gpio.h"
#include "flash.h"
#include "clock.h"
#include "error.h"
#include "pwrmgr.h"
#include "user_data.h"
#include "peripheral.h"
#include "rom_sym_def.h"
#include "uart_process.h"
#include "global_config.h"
#include "halPeripheral.h"
#include "simpleBLEPeripheral.h"
#include "readFlash.h"
#include "user_Bz.h"

#define   DUAL_BANK_MODE 		 0                        /**<dual bank upgrade.*/
#define   SINGLE_BANK_MODE 		 1                        /**< single bank upgrade .*/


#define PIN_DEBONCE_TIME	10
#define PIN_DETECTION_TIME	30000

#define UART_REC_TIMEOUT	50000

#define UART_SEND_ONCE_SIZE 64


uint8_t Hal_TaskID;

uart_data_t uart_rx_data;
uart_data_t uart_tx_data;

uint8_t uart_send_buf[UART_SEND_ONCE_SIZE];
uint8_t uart_send_buff[UART_BUF_SIZE];

uint32_t uart_prev_time = 0;
uint8_t frame_start = 0;
uint8_t at_frame = 0;
uint8_t status_change = 0;
uint8_t uart_tx_status = 0;

typedef struct {
	uint32_t flag_updataNumber;		//Flag: 0xAA55 ,updateFile number ??0?,??BootLoader OTA?bank????;??1?,???bank??????;????????????
	uint32_t updateFile_addr;		//updateFile 1 address in flash
	uint32_t bin_lenght;			//ota bin file lenght
	uint32_t updateFile_type;		//0-BootLoader????;1-????
	uint32_t updateFile_checksum;	//file CRC16 checksum
	uint32_t updateFile_addr1;		//updateFile 1 address in flash
	uint32_t bin_lenght1;			//ota bin file lenght
	uint32_t updateFile_type1;		//0-BootLoader????;1-????
	uint32_t updateFile_checksum1;	//file CRC16 checksum
}OtaUpdateInfo_t;
OtaUpdateInfo_t  bootloaderUpdateInfo = {0xff};

/**
 * @fn      void HalPeripheral_Init(uint8 task_id)
 * @brief   Peripheral initialization
 * @param   task_id
 * @return  none
 */
void __ATTR_SECTION_SRAM__ uart_receive_callback(uart_Evt_t* pev)
{
	switch(pev->type)
	{
		case UART_EVT_TYPE_RX_DATA:
		case UART_EVT_TYPE_RX_DATA_TO:
		{
			uint8_t i;
            
            if(uart_rx_data.wr == uart_rx_data.rd)
            {
                uart_prev_time = (TIME_BASE - ((AP_TIM3->CurrentCount) >> 2));
            }
            
			for(i=0; i<pev->len; i++)
            {
                if( (uart_rx_data.wr - uart_rx_data.rd) < UART_BUF_SIZE )
                {
                    uart_rx_data.data[(uart_rx_data.wr+i)&(UART_BUF_SIZE-1)] = pev->data[i];
                }
                else
                {
//                    LOG("ble full\r\n");
                    break;
                }
			}
            uart_rx_data.wr += i;
            osal_stop_timerEx(Hal_TaskID, USR_UART_RCV_DATA);
            if( (ATT_GetCurrentMTUSize(gapConnHandle)-3) > (uart_rx_data.wr-uart_rx_data.rd) )
            {
                osal_start_timerEx(Hal_TaskID, USR_UART_RCV_DATA, 50);
            }
            else
            {
                osal_set_event(Hal_TaskID, USR_UART_RCV_DATA);
                
                uint32_t uart_curr_time = (TIME_BASE - ((AP_TIM3->CurrentCount) >> 2));
                
                if( (!frame_start) && (TIME_DELTA(uart_curr_time, uart_prev_time) > UART_REC_TIMEOUT) )
                {
                    frame_start = true;
                }
            }
		}
		break;
		
		case UART_EVT_TYPE_TX_COMPLETED:
//			LOG("tx completed\r\n");
            uart_tx_status = 0;
            osal_stop_timerEx(Hal_TaskID, USR_UART_SEND_DATA);
            osal_set_event(Hal_TaskID, USR_UART_SEND_DATA);
		break;
	}
}

void on_bleuartServiceEvt(bleuart_Evt_t* pev)
{
    bool status_changed = false;
	switch(pev->ev){
        case bleuart_EVT_TX_NOTI_DISABLED:
            
        break;
        
        case bleuart_EVT_TX_NOTI_ENABLED :
            //LOG("BUP_OSAL_EVT_NOTIFY_DATA\n");
        break;
        
        case bleuart_EVT_BLE_DATA_RECIEVED:
//            LOG("ble rec:");
            if(osal_memcmp(pev->data,"WSD_OTA",7)){
                status_change = STATUS_OTA;
                status_changed = true;
            }
            else if(osal_memcmp(pev->data,"CSRESET",7)){
                status_change = STATUS_RESET;
                status_changed = true;
            }else if(osal_memcmp(pev->data,"BZ_PWM",6))
            {
                SwithBZPWM(pev->data[6]);
                status_changed = true;
            }else if(osal_memcmp(pev->data,"RDF",3))    //RDF+UNIT32+UNIT16
            {
                if(pev->param == 9)
                {
                    SetReadFlashParament(&pev->data[3],pev->param-3);
                }
            }
            if(status_changed==true){
                peripheral_task_set(TASK_ACTION_START,USR_UART_SEND_DATA,NULL);
            }else{
            //    LOG("ble Rec:");
                for(uint8 i=0; i<pev->param; i++)
                {
                    if( (uart_tx_data.wr - uart_tx_data.rd) < UART_BUF_SIZE )
                    {
                        uart_tx_data.data[(uart_tx_data.wr++)&(UART_BUF_SIZE-1)] = pev->data[i];
                    }
                    else
                    {
                        LOG("f");
                        break;
                    }
                //    LOG("%x ", pev->data[i]);
                }
            //    LOG("\r\n");
	            peripheral_task_set(TASK_ACTION_START,USR_UART_SEND_DATA,NULL);
            }
        break;
        
        default:
        
        break;
	}
}

void wakeup_pin_hdl(GpioPin_t pin,gpio_polarity_e type)
{
    if(pin == WAKEUP_PIN)
    {
        osal_stop_timerEx(Hal_TaskID, USR_WAKEUP_PIN_DET);
        osal_start_timerEx(Hal_TaskID, USR_WAKEUP_PIN_DET, PIN_DEBONCE_TIME);
    }
}

/**
 * @fn      void HalPeripheral_Init(uint8 task_id)
 * @brief   Peripheral initialization
 * @param   task_id
 * @return  none
 */
void HalPeripheral_Init(uint8 task_id)
{
	Hal_TaskID = task_id;
    
    HalGpioPinInit(WAKEUP_PIN, GPIO_INPUT);
    HalGpioPupdConfig(WAKEUP_PIN, GPIO_PULL_UP);
    HalGpioWkupConfig(WAKEUP_PIN, POL_FALLING);
    HalGpioRegister(WAKEUP_PIN, wakeup_pin_hdl, wakeup_pin_hdl);
    
    HalGpioPinInit(BT_STATUS_PIN, GPIO_OUTPUT);
	HalGpioPupdConfig(BT_STATUS_PIN, GPIO_PULL_UP);
    HalGpioSet(BT_STATUS_PIN, Bit_ENABLE);
    
    uart_Cfg_t cfg = {
		.tx_pin = P20,
		.rx_pin = P18,
		.baudrate = baud_table[user_data.baud],
		.use_fifo = TRUE,
		.hw_fwctrl = FALSE,
		.use_tx_buf = TRUE,
		.parity     = FALSE,
		.evt_handler = uart_receive_callback,
	};
	HalUartInit(UART1, cfg);//uart init
    HalUartSetTxBuf(UART1, uart_send_buff, UART_BUF_SIZE);
    
    osal_memcpy(uart_send_buf, "OK\r\n", 4);
    HalUartSendBuf(UART1, uart_send_buf, 4);
    
    osal_start_timerEx(Hal_TaskID, USR_WAKEUP_PIN_DET, PIN_DEBONCE_TIME);
}

/**
* @fn enter_sigle_bank_ota(void)
* @brief write  update_info_flag to enter sigle bank ota
* @param none
* @return none
*/
void enter_sigle_bank_ota(void)
{
		bootloaderUpdateInfo.flag_updataNumber = 0x0000aa55;

		HalFlashErase(FLASH_BOOTLOADER_UPDATE_INFO_ADDR >> 12);
		HalFlashWrite(FLASH_BOOTLOADER_UPDATE_INFO_ADDR,(uint8_t *)&bootloaderUpdateInfo, 4);

}

/**
 * @fn      void uart_send_process(void)
 * @brief   uart data send event process
 * @param   none
 * @return  none
 */
void uart_send_process(void)
{
    uint16_t len;
    
    if(uart_tx_data.wr != uart_tx_data.rd)
    {
        if(!uart_tx_status)
        {
            len = uart_tx_data.wr - uart_tx_data.rd;
            if(len > UART_SEND_ONCE_SIZE)
            {
                len = UART_SEND_ONCE_SIZE;
            }
            for(uint16_t i=0; i<len; i++)
            {
                uart_send_buf[i] = uart_tx_data.data[(uart_tx_data.rd++)&(UART_BUF_SIZE-1)];
            }
            
            while(HalUartGetTxReady(UART1) == ERR_BUSY);
            LOG("send:%d\r\n", len);
            //LOG("send:%d\r\n", len);
            HalUartSendBuf(UART1, uart_send_buf, len);
            uart_tx_status = true;
        }
        if(uart_tx_data.wr != uart_tx_data.rd)
        {
            peripheral_task_set(TASK_ACTION_START, USR_UART_SEND_DATA, (len/(baud_table[user_data.baud]/10)+1));
        }
    }
    else
    {
        uart_tx_status = false;
        switch(status_change)
        {
            case STATUS_BAUD:
                while(HalUartGetBusy(UART1) == ERR_BUSY);
                HalUartBaudSet(UART1, baud_table[user_data.baud]);
            break;
            
            case STATUS_POWEROFF:
            {
                pwroff_cfg_t cfg;
        
                cfg.pin = WAKEUP_PIN;
                cfg.type = POL_FALLING;
                cfg.on_time = 100;
                
                hal_pwrmgr_poweroff(&cfg, 1);
            }
            break;
            
            case STATUS_RESET:
            case STATUS_RESTORE:
                NVIC_SystemReset();
                while(1);
            
            case STATUS_OTA:
            #if (OTA_BANK_MODE == DUAL_BANK_MODE)
                LOG("reboot to dul ota.\r\n");
                write_reg(0x1FFF18FC,0x55AAAA55);
                GAPRole_TerminateConnection();
                WaitMs(500);
                NVIC_SystemReset();
            #elif (OTA_BANK_MODE == SINGLE_BANK_MODE)
                LOG("reboot to single ota.\r\n");
                enter_sigle_bank_ota();
                GAPRole_TerminateConnection();
                WaitMs(500);
                NVIC_SystemReset();
            #endif
                while(1);
            
            default:
                
            break;
        }
        status_change = 0;
    }
}

/**
 * @fn      uint16 HalPeripheral_ProcessEvent( uint8 task_id, uint16 events )
 * @brief   Peripheral event process
 * @param   task_id
 * @param	events
 * @return  none
 */
static uint8_t uart_buf[35] = {0};
uint16 HalPeripheral_ProcessEvent( uint8 task_id, uint16 events )
{
	if(task_id != Hal_TaskID)
    {
		return 0;
	}
	
	if( events & USR_UART_RCV_DATA )
    {
        uint16_t i;
		uint16_t len;
        static uint8_t times = 0;
        static uint8_t send_times = 0;
        
//        LOG("USR_UART_RCV_DATA%d %d %d\r\n", frame_start, uart_rx_data.wr, uart_rx_data.rd);
        if(!frame_start || at_frame)
        {
            frame_start = true;
            while( (uart_rx_data.wr-uart_rx_data.rd) >= 4 )
            {
                if( (uart_rx_data.data[uart_rx_data.rd&(UART_BUF_SIZE-1)] == 'A') && \
                    (uart_rx_data.data[(uart_rx_data.rd+1)&(UART_BUF_SIZE-1)] == 'T') )
                {
                    len = uart_rx_data.wr - uart_rx_data.rd - 2;
                    if(len > 35)
                    {
                        len = 35;
                    }
                    osal_memset(uart_buf, 0, 35);
                    for(i=0; i<len; i++)
                    {
                        uart_buf[i] = uart_rx_data.data[(uart_rx_data.rd+2+i)&(UART_BUF_SIZE-1)];
                    }
                    // uart analysis
                    i = uart_analysis(uart_buf);
                    LOG("AT analysis%d\r\n", i);
                    if(i)
                    {
                        if(i == 0xFF)
                        {
                            times++;
                            if( (len > 35) || (times > 3) )
                            {
                                times = 0;
                                at_frame = false;
                            }
                            else
                            {
                                at_frame = true;
                            }
                            break;
                        }
                        else
                        {
                            times = 0;
                            at_frame = false;
                            uart_rx_data.rd += i;
                        }
                    }
                    else
                    {
                        break;
                    }
                }
                else
                {
                    break;
                }
            }
        }
//        LOG("AT_FRAME:%d\r\n", at_frame);
        if(!at_frame)
        {
            if(!connect_status)
            {
                uart_rx_data.rd = uart_rx_data.wr;
            }
            if(uart_rx_data.rd != uart_rx_data.wr)
            {
                len = uart_rx_data.wr - uart_rx_data.rd;
            }
            else
            {
                len = 0;
            }
            if(len)
            {
                bStatus_t ret;
                attHandleValueNoti_t notify_data;
                
                if(len > (ATT_GetCurrentMTUSize(gapConnHandle)-3))
                {
                    len = ATT_GetCurrentMTUSize(gapConnHandle) - 3;
                }
//                LOG("uart data send:");
                for(i=0; i<len; i++)
                {
//                    LOG("%x ", uart_rx_data.data[(uart_rx_data.rd+i)&(UART_BUF_SIZE-1)]);
                    notify_data.value[i] = uart_rx_data.data[(uart_rx_data.rd+i)&(UART_BUF_SIZE-1)];
                }
//                LOG("\r\n");
                notify_data.len = len;
                ret = bleuart_Notify(gapConnHandle, &notify_data);
//                LOG("ble send:%d %d\r\n", len, ret);
                if(ret == SUCCESS)
                {
                    send_times = 0;
                    uart_rx_data.rd += len;
                }
                else
                {
                    send_times++;
                    if(send_times >= 10)
                    {
                        uart_rx_data.rd += len;
                        send_times = 0;
                    }
                }
            }
        }
        
        osal_stop_timerEx(Hal_TaskID, USR_UART_RCV_DATA);
        if(uart_rx_data.rd != uart_rx_data.wr)
        {
            if( ((ATT_GetCurrentMTUSize(gapConnHandle)-3) >= (uart_rx_data.wr-uart_rx_data.rd)) || (send_times != 0) )
            {
                osal_stop_timerEx(Hal_TaskID, USR_UART_RCV_DATA);
                osal_set_event(Hal_TaskID, USR_UART_RCV_DATA);
            }
            else
            {
//            LOG("again\r\n");
                osal_start_timerEx(Hal_TaskID, USR_UART_RCV_DATA, 50);
            }
        }
        else
        {
            frame_start = false;
            osal_clear_event(Hal_TaskID, USR_UART_RCV_DATA);
        }
		
        return ( events ^ USR_UART_RCV_DATA );
    }
    
    if( events & USR_UART_SEND_DATA )
    {
        uart_send_process();
        
        return ( events ^ USR_UART_SEND_DATA );
    }
    
    if( events & USR_WAKEUP_PIN_DET )
    {
        static uint8_t det_times = 0;
        
        if( HalGpioGet(WAKEUP_PIN) )
        {
            det_times++;
            if(det_times > 3)
            {
                det_times = 0;
                LOG("sleep\r\n");
                hal_pwrmgr_unlock(MOD_GPIO);
            }
            else
            {
                osal_stop_timerEx(Hal_TaskID, USR_WAKEUP_PIN_DET);
                osal_start_timerEx(Hal_TaskID, USR_WAKEUP_PIN_DET, PIN_DEBONCE_TIME);
            }
        }
        else
        {
            LOG("wakeup\r\n");
            det_times = 0;
            hal_pwrmgr_lock(MOD_GPIO);
            osal_stop_timerEx(Hal_TaskID, USR_WAKEUP_PIN_DET);
            osal_start_timerEx(Hal_TaskID, USR_WAKEUP_PIN_DET, PIN_DETECTION_TIME);
        }
        
        return ( events ^ USR_WAKEUP_PIN_DET );
    }
    
    if( events & USR_EVT_OTHER)
    {
        return ( events ^ USR_EVT_OTHER );
    }
	
    // Discard unknown events
    return 0;
}

/**
 * @fn		void peripheral_task_set(uint8 action, uint16 event, uint32 time)
 * @brief	
 * @param	none
 * @return	none
 */
void peripheral_task_set(uint8 action, uint16 event, uint32 time)
{
    osal_stop_timerEx(Hal_TaskID, event);
    if(action == TASK_ACTION_START)
    {
        if(time)
        {
            osal_start_timerEx(Hal_TaskID, event, time);
        }
        else
        {
            osal_set_event(Hal_TaskID, event);
        }
    }
}

/*********************************************************************
*********************************************************************/
